package com.qf.commons.redis.lock;

import com.qf.commons.core.utils.ApplicationUtils;
import lombok.extern.slf4j.Slf4j;
import org.redisson.Redisson;
import org.redisson.api.RLock;

import java.util.concurrent.TimeUnit;

@Slf4j
public class Clock {

    private static Redisson redisson;

    static {
        //通过非注入的方式，从IOC容器中获取指定类型的Bean对象
        redisson = ApplicationUtils.getBean(Redisson.class);
    }

    /**
     * 尝试获得分布式锁没有获得则直接返回false
     * @param key - 分布式锁的名称
     * @return
     */
    public static boolean tryLock(String key){
        log.info("[cluster lock] - 尝试获取分布式锁  - {}",key);
        RLock lock =  redisson.getLock(key);
        if (lock.tryLock()){
            log.info("[cluster lock succ] - 获取分布式锁成功 - {}",key);
            ClockThreadLocal.set(lock);
            return true;
        }
        log.info("[cluster lock fail] - 获取分布式锁失败 - {}",key);
        return false;
    }

    /**
     * 阻塞式获得分布式锁，如果没有获得分布式锁，则当前方法等待
     * @param key
     */
    public static  void bLock(String key){
        log.info("[cluster lock] - 尝试获取分布式锁 - {}",key);
        RLock lock = redisson.getLock(key);
        while (!lock.tryLock());
        ClockThreadLocal.set(lock);
        log.info("[cluster lock succ] - 获取分布式锁成功 - {}",key);
    }

    /**
     * 尝试获得分布式锁，如果超过单位时间没获得分布式锁，则返回false
     * @param key
     * @return
     */
    public static boolean tryLockTimeout(String key, Long timeout, TimeUnit unit){
        log.info("[cluster lock ]-尝试获取分布式锁 - {}",key);
        RLock lock = redisson.getLock(key);
        try {
            boolean flag = lock.tryLock(timeout,unit);
            if (flag){
                ClockThreadLocal.set(lock);
                log.info("[cluster lock succ] - 获取分布式锁成功 - {}",key);
                return true;
            }
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        log.info("[cluster lock fail ] - 获取分布式锁失败 - {}",key);
        return false;
    }

    /**
     * 解除分布式锁
     */
    public static  void unlock(){
       RLock rLock = ClockThreadLocal.get();
       log.info("[cluster lock] - 解除分布式锁");
       if (rLock != null && rLock.isLocked()){
           rLock.unlock();
       }
       ClockThreadLocal.clear();
    }
}
